from typing import List, Optional, Union
from datetime import datetime, timedelta

from fastapi.encoders import jsonable_encoder
from jose import jwt

from odoo.addons.fastapi_odoo_bridge.core.response import custom_response
from odoo.api import Environment
from odoo.addons.fastapi.dependencies import odoo_env
from odoo.addons.fastapi_odoo_bridge.core.token import JWTUtils, SECRET_KEY, ALGORITHM
from fastapi import APIRouter, Depends, Body, Header, Request, Query
from fastapi.security import OAuth2PasswordRequestForm
from ...basemodels.vo.common.first_level import Token, UserRegistration, UserFindPassword
from ...basemodels.vo.common.sec_level import User
from odoo.addons.fastapi_odoo_bridge.core.header import verify_token, set_lang
from ...functions.login import Login
from ...basemodels.vo.center_area.user_center import UserInfo
from odoo.addons.fastapi_odoo_bridge.core.basemodel import CommonResponse

router = APIRouter(tags=['登录'])

ACCESS_TOKEN_EXPIRE_MINUTES = 30  # 访问令牌过期分钟
user_model = 'rp.customer'
# 创建JWT集成对象
jwt_utils = JWTUtils(model=user_model)
# 创建crypt_context对象
jwt_utils.create_crypt_context()
# 创建OAuth2PasswordBearer
jwt_utils.create_oauth2_schema('/web/rp_login')


@router.post('/rp_login',
             summary='登陆',
             description='登陆',
             response_model=Union[list, dict, List[dict]])
@custom_response
@set_lang
async def login_for_access_token(request: Request, form_data: OAuth2PasswordRequestForm = Depends(),
                                 env: Environment = Depends(odoo_env), Accept_Language: Optional[str] = Header()):
    # 1、给JWTUtils对象注入odoo_env
    jwt_utils.env = env
    # 2、校验用户
    user = jwt_utils.authenticate_user(form_data.username, form_data.password)
    # 3、创建token
    encode_jwt = jwt_utils.created_access_token(user.id, timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))

    result = {'access_token': encode_jwt, 'token_type': "Bearer", 'user': User(__from_odoo=user, __env=env)}
    # 存入Session中
    request.session['order_customer_id'] = user.id
    return jsonable_encoder(CommonResponse(code='200', msg='success', data=result))


@router.post('/rp_register',
             summary='注册',
             description='注册',
             response_model=Union[list, dict, List[dict]]
             )
@custom_response
@set_lang
async def rp_register(user: UserRegistration = Body(..., description='注册'),
                      env: Environment = Depends(odoo_env), Accept_Language: Optional[str] = Header()):
    operation = Login(env)

    # 判断登录名是否重复，邮箱作为用户名【需要判断唯一】
    dicts = {'username': user.email}
    if not operation.jwt_repeat_datas(user_model, dicts):
        return {'code': 401,
                'message': '该登录邮箱已被注册'}

    # 正则表单式验证邮箱正确行
    if not operation.jwt_email_format(user.email):
        return {'code': 401,
                'message': '邮箱格式不正确'}
    if len(user.password) < 6:
        return {'code': 401,
                'message': '注册密码要大于6位'}

    # 密码加密
    password = jwt_utils.encrypt_password(plain_password=user.password)
    new_user = env[user_model].create([{
        'first_name': user.first_name,
        'last_name': user.last_name,
        'username': user.email,
        'email': user.email,
        'password': password
    }])
    # 创建token
    encode_jwt = jwt_utils.created_access_token(new_user.id, timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
    return jsonable_encoder(CommonResponse(code='200', msg='success', data={'access_token': encode_jwt, 'token_type': "Bearer"}))


@router.get('/send/mail/verify',
            summary='邮箱发送验证码',
            description='邮箱发送验证码',
            response_model=Union[list, dict, List[dict]]
            )
async def send_mail_verify(env: Environment = Depends(odoo_env),
                           mail: str = Query(..., description='邮箱')):
    result = Login(env).send_mail_verify(act_one='login_verify', mail=mail)
    return result


@router.get('/verify/mail/code',
            summary='邮箱验证码验证',
            description='邮箱验证码验证',
            response_model=Union[list, dict, List[dict]]
            )
async def verify_mail_code(env: Environment = Depends(odoo_env),
                           mail: str = Query(..., description='邮箱'),
                           verifyt_code: str = Query(..., description='验证码')):
    result = Login(env).verify_mail_code(mail=mail, verifyt_code=verifyt_code)
    return result


@router.post('/find/password',
             summary='找回密码',
             description='找回密码',
             response_model=Union[list, dict, List[dict]]
             )
@custom_response
async def rp_register(info: UserFindPassword = Body(..., description='找回密码'),
                      env: Environment = Depends(odoo_env)):
    result = Login(env).find_password(info=info, jwt_utils=jwt_utils)
    return result


@router.post(
    path='/token/transform/user',
    description='获取用户信息',
    summary='获取用户信息',
    response_model=Union[list, dict, List[dict]]
)
@custom_response
async def token_transform_user(token: str = Query(..., description='Token'), env: Environment = Depends(odoo_env)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        rp_customer_id = env['rp.customer'].search([('id', '=', payload.get('userID'))])
        user_info = UserInfo(__from_odoo=rp_customer_id, __env=env)
        return {
            'code': 200,
            'msg': '获取成功',
            'data': user_info
        }
    except jwt.ExpiredSignatureError:
        return {
            'code': 401,
            'msg': 'Token过期'
        }
    except jwt.JWTError:
        return {
            'code': 401,
            'msg': 'Token无效'
        }


@router.get(
    path='/session_remove',
    summary='清除剩余数据',
    description='清除剩余数据（用于用户清除缓存，登出，Token过期失效后的Session清除操作）',
    response_model=Union[list, dict, List[dict]]
)
@custom_response
async def session_remove(request: Request):
    # 获取到登录用户
    login_user = request.session.get('order_customer_id')
    if login_user:
        # 清除登录用户
        request.session.pop('order_customer_id')
    return CommonResponse(code='200', msg='清理成功', data=[])
